import { App } from '@/models/app'
import { useAsyncState, useFetch } from '@vueuse/core'
import { readonly, ref, watch } from 'vue'
import { dbFile2bytes } from './utils'

type TResourceType = 'DbFile' | 'echarts-map'

type TAction = {
    name: TActionName
    args: any
}
type TActionName = 'fetch' | 'unzip'

export interface WebResource {
    id: string
    type: TResourceType
    input: any
    actionPipe: TAction[]
}

export type TWebResourcesService = ReturnType<typeof getServices>


export function getServices(app: App) {
    const id2resourceMapping = new Map<string, () => any>()
    app.webResources.forEach(wr => {
        const wrGetter = BuildWebResourceGetter(wr)
        id2resourceMapping.set(wr.id, wrGetter)
    })

    function getResource(id: string) {
        if (!id2resourceMapping.has(id)) {
            throw new Error(`web Resource[${id}] not found`);
        }

        return id2resourceMapping.get(id)!()
    }

    function getDbFile() {
        const fileBs64 = getResource('DbFile') as string
        const { state: fileBytes } = useAsyncState(async () => await dbFile2bytes(fileBs64), null)
        return readonly(fileBytes)
    }

    return {
        getResource,
        getDbFile
    }
}


function fetchAction(args: any) {
    const { data } = useFetch(args.url, args.options).json()
    return data
}

function cacheFn(fn: () => any) {
    let result = null as any

    return () => {
        if (result) {
            return result
        }

        result = fn()
        return result
    }
}

function getDbFileWebResource(wr: WebResource) {
    const getter = cacheFn(() => wr.input)
    return getter
}

function getEChartsMapWebResource(wr: WebResource) {

    if (wr.input) {
        const getter = cacheFn(() => {
            (echarts as any).registerMap(wr.id, { geoJSON: wr.input });
            return ref(true)
        })
        return getter
    }

    const fetchArgs = wr.actionPipe[0]
    const args = fetchArgs.args as {
        url: string
        options: any
    }

    const getter = cacheFn(() => {
        const { isFinished, data } = useFetch(args.url, args.options).get().json()

        watch(data, data => {
            (echarts as any).registerMap(wr.id, { geoJSON: data });
        })

        return isFinished
    })
    return getter
}

export function BuildWebResourceGetter(wr: WebResource) {
    switch (wr.type) {
        case 'DbFile':
            return getDbFileWebResource(wr)
            break;

        case 'echarts-map':
            return getEChartsMapWebResource(wr)
            break;

        default:
            throw new Error("not suport");
            break;
    }
}


